package client

import (
	j "encoding/json"
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"net/url"
	"strconv"
	"trade/logger"
	"trade/model"
)

type Client struct {
	Sign       *Sign
	host       string
	pathPrefix string
	scheme     string
}

/// 行情API
const MarketEndpoint = "https://api.hbdm.com/"

/// 交易API
const TradeEndpoint = "https://api.hbdm.com/"

/// 全局API
const Endpoint = "https://api.hbdm.com/"

/// 创建新客户端
func NewClient(endpoint, accessKeyId, accessKeySecret string) (*Client, error) {
	urlInfo, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}

	client := &Client{
		Sign:       NewSign(accessKeyId, accessKeySecret),
		host:       urlInfo.Host,
		pathPrefix: urlInfo.Path,
		scheme:     urlInfo.Scheme,
	}
	if client.pathPrefix == "/" {
		client.pathPrefix = ""
	}

	return client, nil
}

/// 发送请求
func (c *Client) Request(method, path string, data ParamData) (*simplejson.Json, error) {
	return SendRequest(c.Sign, method, c.scheme, c.host, c.pathPrefix+path, data)
}

type Order struct {
	Symbol         string  `json:"symbol"`
	ContractType   string  `json:"contract_type"`
	ContractCode   string  `json:"contract_code"`
	ClientOrderId  int64   `json:"client_order_id"`
	Price          float64 `json:"price"`
	Volume         int64   `json:"volume"`
	Direction      string  `json:"direction"`
	Offset         string  `json:"offset"`
	LeverRate      int     `json:"lever_rate"`
	OrderPriceType string  `json:"order_price_type"`
}

type ForceOrder struct {
	ContractType string `json:"contract_type"`
	Symbol       string `json:"symbol"`
	Volume       int64  `json:"volume"`
	Direction    string `json:"direction"`
}

type OrderResult struct {
	Status string `json:"status"`
	Data   struct {
		OrderID       int64  `json:"order_id"`
		OrderIDStr    string `json:"order_id_str"`
		ClientOrderId string `json:"client_order_id"`
	} `json:"data"`
	TS int64 `json:"ts"`
}

/// 下单
func (c *Client) Order(o Order) (*OrderResult, error) {
	price := fmt.Sprintf("%.3f", o.Price)
	var err error
	o.Price, err = strconv.ParseFloat(price, 64)
	if err != nil {
		return nil, err
	}
	b, _ := j.Marshal(o)
	var p ParamData
	_ = j.Unmarshal(b, &p)
	json, err := c.Request("POST", "/api/v1/contract_order", p)
	if err != nil {
		return nil, err
	}
	// logger.Log.Debug(json)
	b, _ = j.Marshal(json)
	var r OrderResult
	_ = j.Unmarshal(b, &r)
	return &r, nil
}

/// 强制平仓
func (c *Client) ForceOrder(o ForceOrder) (*OrderResult, error) {
	b, _ := j.Marshal(o)
	var p ParamData
	_ = j.Unmarshal(b, &p)
	json, err := c.Request("POST", "/api/v1/lightning_close_position", p)
	if err != nil {
		return nil, err
	}
	// logger.Log.Debug(json)
	b, _ = j.Marshal(json)
	var r OrderResult
	_ = j.Unmarshal(b, &r)
	return &r, nil
}

type QueryOrder struct {
	OrderID       string `json:"order_id"`
	ClientOrderId string `json:"client_order_id"`
	Symbol        string `json:"symbol"`
}

type CancelOrderResult struct {
	OrderID       string `json:"order_id"`
	ClientOrderId string `json:"client_order_id"`
	Symbol        string `json:"symbol"`
}

/// 撤单
func (c *Client) CancelOrder(o QueryOrder) bool {
	b, _ := j.Marshal(o)
	var p ParamData
	_ = j.Unmarshal(b, &p)
	json, err := c.Request("POST", "/api/v1/contract_cancel", p)
	if err != nil {
		logger.Log.Error(err)
		return false
	}
	status, err := json.Get("status").String()
	if err != nil {
		logger.Log.Error(err, json)
		return false
	}
	if status == "ok" {
		return true
	}
	return false
}

const (
	STATUS_READY_SUB                = 1
	STATUS_READY2_SUB               = 2
	STATUS_SUBMIT                   = 3
	STATUS_PART_SUCCESS             = 4
	STATUS_PART_SUCCESS_WITH_CANCEL = 5
	STATUS_ALL_SUCCESS              = 6
	STATUS_ALL_CANCEL               = 7
	STATUS_CANCEL_ING               = 11
)

type OrderDetail struct {
	OrderID        int64   `json:"order_id"`
	OrderIDStr     string  `json:"order_id_str"`
	ContractType   string  `json:"contract_type"`
	ContractCode   string  `json:"contract_code"`
	Volume         float64 `json:"volume"`
	Price          float64 `json:"price"`
	OrderPriceType string  `json:"order_price_type"`
	Direction      string  `json:"direction"`
	Offset         string  `json:"offset"`
	LeverRate      int     `json:"lever_rate"`
	TS             int64   `json:"ts"`
	ClientOrderId  int64   `json:"client_order_id"`
	Symbol         string  `json:"symbol"`
	CreatedAt      int64   `json:"created_at"`
	Status         int     `json:"status"`
	TradeVolume    float64 `json:"trade_volume"`
	Profit         float64 `json:"profit"`
}

type OrderDetailResult struct {
	Status string        `json:"status"`
	Data   []OrderDetail `json:"data"`
}

/// 订单详情
func (c *Client) OrderDetail(o QueryOrder) (OrderDetail, error) {
	b, _ := j.Marshal(o)
	var p ParamData
	_ = j.Unmarshal(b, &p)
	json, err := c.Request("POST", "/api/v1/contract_order_info", p)
	if err != nil {
		logger.Log.Error(err)
		return OrderDetail{}, err
	}
	// logger.Log.Debug(json)
	b, _ = j.Marshal(json)
	var r OrderDetailResult
	err = j.Unmarshal(b, &r)
	if err != nil {
		logger.Log.Error(err)
		return OrderDetail{}, err
	}
	if r.Status == "ok" {
		return r.Data[0], err
	}
	return OrderDetail{}, errors.New(r.Status)
}

type PositionResult struct {
	Status string           `json:"status"`
	Data   []model.Position `json:"data"`
	TS     int64            `json:"ts"`
}

/// 持仓情况
func (c *Client) PositionInfo(symbol string) ([]model.Position, error) {
	js, err := c.Request("POST", "/api/v1/contract_position_info", ParamData{"symbol": symbol})
	if err != nil {
		return nil, err
	}
	var r PositionResult
	b, _ := j.Marshal(js)
	_ = j.Unmarshal(b, &r)
	return r.Data, nil
}

/// 订单详情
func (c *Client) ContractInfo(symbol string) (*simplejson.Json, error) {
	return c.Request("GET", "/api/v1/contract_contract_info", ParamData{"symbol": symbol})
}

/// 订单列表
func (c *Client) OrderList(symbol string, tradeType int) (*simplejson.Json, error) {
	return c.Request("POST", "/api/v1/contract_matchresults", ParamData{"symbol": symbol, "trade_type": tradeType, "create_date": 1})
}

type AccountResult struct {
	Status string          `json:"status"`
	Data   []model.Account `json:"data"`
	TS     int64           `json:"ts"`
}

/// 账户信息
func (c *Client) AccountInfo(symbol string) (model.Account, error) {
	jBytes, err := c.Request("POST", "/api/v1/contract_account_info", ParamData{"symbol": symbol})
	if err != nil {
		return model.Account{}, err
	}
	var r AccountResult
	b, err := j.Marshal(jBytes)
	_ = j.Unmarshal(b, &r)
	if len(r.Data) < 1 {
		return model.Account{}, errors.New("账户不存在!")
	}
	return r.Data[0], nil
}

type IndexResult struct {
	Status string        `json:"status"`
	Data   []model.Index `json:"data"`
	TS     int64         `json:"ts"`
}

/// 指数信息
func (c *Client) ContractIndexInfo(symbol string) (model.Index, error) {
	jBytes, err := c.Request("GET", "/api/v1/contract_index", ParamData{"symbol": symbol})
	if err != nil {
		return model.Index{}, err
	}
	var r IndexResult
	b, err := j.Marshal(jBytes)
	_ = j.Unmarshal(b, &r)
	if len(r.Data) < 1 {
		return model.Index{}, errors.New("指数不存在!")
	}
	return r.Data[0], nil
}

/// 空头与多头比例
func (c *Client) PositionRatio(symbol string, period string) (model.RatioResult, error) {
	jBytes, err := c.Request("GET", "/api/v1/contract_elite_position_ratio", ParamData{"symbol": symbol, "period": period})
	if err != nil {
		return model.RatioResult{}, err
	}
	var r model.RatioResult
	b, err := j.Marshal(jBytes)
	logger.Log.Debug(string(b))
	_ = j.Unmarshal(b, &r)
	return r, nil
}

/// 空头与多头账户比例
func (c *Client) PositionAccountRatio(symbol string, period string) (model.RatioResult, error) {
	jBytes, err := c.Request("GET", "/api/v1/contract_elite_account_ratio", ParamData{"symbol": symbol, "period": period})
	if err != nil {
		return model.RatioResult{}, err
	}
	var r model.RatioResult
	b, err := j.Marshal(jBytes)
	logger.Log.Debug(string(b))
	_ = j.Unmarshal(b, &r)
	return r, nil
}
